import os
import sys
import sqlite3
import subprocess
import datetime
import shutil
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.uix.popup import Popup
from kivy.uix.listview import ListItemButton
from kivy.uix.spinner import Spinner
from kivy.clock import Clock
from kivy.properties import StringProperty, ListProperty, ObjectProperty, BooleanProperty
from kivy.core.window import Window
from kivy.storage.jsonstore import JsonStore
import threading
import time

# 设置中文字体支持
import kivy
kivy.require('2.0.0')

# 调整窗口大小以模拟手机屏幕
Window.size = (480, 800)

class ScanThread(threading.Thread):
    """文件扫描线程"""
    def __init__(self, root_paths, extensions=None, callback=None):
        super().__init__()
        self.root_paths = root_paths
        self.extensions = extensions if extensions is not None else []
        self.running = True
        self.found_files = []
        self.callback = callback
        self.total_files = 0
    
    def run(self):
        for root_path in self.root_paths:
            if not self.running:
                break
                
            for dirpath, _, filenames in os.walk(root_path):
                if not self.running:
                    break
                    
                for filename in filenames:
                    if not self.running:
                        break
                        
                    # 检查文件扩展名是否在指定的列表中
                    if any(filename.lower().endswith(ext.lower()) for ext in self.extensions):
                        try:
                            full_path = os.path.join(dirpath, filename)
                            file_size = os.path.getsize(full_path)
                            # 获取文件创建时间
                            creation_time = os.path.getctime(full_path)
                            # 格式化为可读时间
                            formatted_time = datetime.datetime.fromtimestamp(creation_time).strftime('%Y-%m-%d %H:%M:%S')
                            
                            file_info = {
                                'name': filename,
                                'path': full_path,
                                'size': self.format_size(file_size),
                                'ext': filename.split('.')[-1].upper(),
                                'created': formatted_time
                            }
                            self.found_files.append(file_info)
                            # 使用Clock.schedule_once确保在主线程更新UI
                            if self.callback:
                                Clock.schedule_once(lambda dt, info=file_info: self.callback(info))
                        except Exception as e:
                            continue
                            
                    self.total_files += 1
                    if self.total_files % 100 == 0:
                        # 更新进度
                        if self.callback:
                            Clock.schedule_once(lambda dt: self.callback({'progress': self.total_files}))
        
        # 扫描完成
        if self.callback:
            Clock.schedule_once(lambda dt: self.callback({'finished': True}))
    
    def stop(self):
        self.running = False
    
    @staticmethod
    def format_size(size_bytes):
        """格式化文件大小为人类可读形式"""
        for unit in ['B', 'KB', 'MB', 'GB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.2f} {unit}"
            size_bytes /= 1024.0
        return f"{size_bytes:.2f} TB"

class FileItem(BoxLayout):
    """文件列表项组件"""
    file_info = ObjectProperty({})
    on_select = ObjectProperty(None)
    
    def __init__(self, file_info, on_select=None, **kwargs):
        super().__init__(**kwargs)
        self.orientation = 'vertical'
        self.file_info = file_info
        self.on_select = on_select
        self.size_hint_y = None
        self.height = 80
        self.padding = 10
        self.spacing = 5
        
        # 创建文件名标签
        self.name_label = Label(text=file_info['name'], font_size='16sp', halign='left', valign='middle', text_size=(self.width, None))
        
        # 创建详细信息行
        details_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=30)
        details_layout.add_widget(Label(text=f"{file_info['ext']}", font_size='12sp', color=(0.5, 0.5, 0.5, 1)))
        details_layout.add_widget(Label(text=f"{file_info['size']}", font_size='12sp', color=(0.5, 0.5, 0.5, 1)))
        details_layout.add_widget(Label(text=f"{file_info['created'][:10]}", font_size='12sp', color=(0.5, 0.5, 0.5, 1)))
        
        self.add_widget(self.name_label)
        self.add_widget(details_layout)
        
        # 添加点击事件
        self.bind(on_touch_down=self.on_touch)
    
    def on_touch(self, instance, touch):
        if self.collide_point(*touch.pos):
            if self.on_select:
                self.on_select(self.file_info)
            return True
        return False
    
    def on_size(self, instance, value):
        self.name_label.text_size = (self.width - 20, None)

class FileTypeSelector(GridLayout):
    """文件类型选择器组件"""
    selected_extensions = ListProperty([])
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.cols = 3
        self.spacing = 5
        self.size_hint_y = None
        self.bind(minimum_height=self.setter('height'))
        
        # 常用文件类型
        self.file_types = {
            # 文档类型
            '.ppt': 'PPT',
            '.pptx': 'PPTX',
            '.doc': 'DOC',
            '.docx': 'DOCX',
            '.pdf': 'PDF',
            '.xls': 'XLS',
            '.xlsx': 'XLSX',
            # 代码文件类型
            '.py': 'Python',
            # 图片类型
            '.jpg': 'JPG',
            '.jpeg': 'JPEG',
            '.png': 'PNG',
            '.gif': 'GIF',
            '.bmp': 'BMP',
            # 视频类型
            '.mp4': 'MP4',
            '.avi': 'AVI',
            '.mov': 'MOV',
            '.wmv': 'WMV'
        }
        
        # 创建复选框
        self.checkboxes = {}
        for ext, name in self.file_types.items():
            box = BoxLayout(orientation='horizontal', size_hint_y=None, height=40, spacing=5)
            checkbox = CheckBox(group='file_type')
            checkbox.bind(active=lambda instance, value, e=ext: self.on_checkbox_change(e, value))
            label = Label(text=name, font_size='14sp', size_hint_x=0.7)
            box.add_widget(checkbox)
            box.add_widget(label)
            self.add_widget(box)
            self.checkboxes[ext] = checkbox
    
    def on_checkbox_change(self, ext, value):
        if value and ext not in self.selected_extensions:
            self.selected_extensions.append(ext)
        elif not value and ext in self.selected_extensions:
            self.selected_extensions.remove(ext)

class FileActionPopup(Popup):
    """文件操作弹出菜单"""
    file_info = ObjectProperty({})
    
    def __init__(self, file_info, on_action=None, **kwargs):
        super().__init__(**kwargs)
        self.file_info = file_info
        self.on_action = on_action
        self.size_hint = (0.8, 0.5)
        self.title = '文件操作'
        
        # 创建内容布局
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        
        # 文件名标签
        content.add_widget(Label(text=file_info['name'], font_size='16sp', halign='center', valign='middle'))
        
        # 操作按钮布局
        actions_layout = GridLayout(cols=2, spacing=5, size_hint_y=1)
        
        # 操作按钮
        actions = [
            ('打开文件', 'open_file'),
            ('打开位置', 'open_location'),
            ('复制路径', 'copy_path'),
            ('添加备注', 'add_note'),
            ('复制文件', 'copy_file'),
            ('重命名', 'rename'),
            ('删除', 'delete')
        ]
        
        for text, action in actions:
            btn = Button(text=text, on_press=lambda instance, a=action: self.do_action(a))
            actions_layout.add_widget(btn)
        
        # 取消按钮
        cancel_btn = Button(text='取消', on_press=self.dismiss)
        
        content.add_widget(actions_layout)
        content.add_widget(cancel_btn)
        
        self.content = content
    
    def do_action(self, action):
        if self.on_action:
            self.on_action(action, self.file_info)
        self.dismiss()

class MobileScannerApp(App):
    """移动版文件扫描应用"""
    status_text = StringProperty('就绪')
    file_count = StringProperty('0')
    search_text = StringProperty('')
    
    def build(self):
        self.root = BoxLayout(orientation='vertical', padding=10, spacing=10)
        self.scan_thread = None
        self.files = []
        self.filtered_files = []
        self.selected_extensions = []
        self.db_path = 'file_notes.db'
        self.init_db()
        
        # 顶部控制区
        control_layout = BoxLayout(orientation='vertical', spacing=10, size_hint_y=None, height=200)
        
        # 路径输入
        path_layout = BoxLayout(orientation='horizontal', spacing=5, size_hint_y=None, height=40)
        self.path_input = TextInput(text='', hint_text='扫描路径', multiline=False, size_hint_x=0.7)
        browse_btn = Button(text='浏览', on_press=self.browse_directory)
        path_layout.add_widget(self.path_input)
        path_layout.add_widget(browse_btn)
        
        # 文件类型选择器（可滚动）
        type_scroll = ScrollView(size_hint_y=None, height=100)
        self.type_selector = FileTypeSelector()
        self.type_selector.bind(selected_extensions=self.on_extensions_change)
        type_scroll.add_widget(self.type_selector)
        
        # 扫描按钮
        scan_layout = BoxLayout(orientation='horizontal', spacing=5, size_hint_y=None, height=40)
        self.scan_btn = Button(text='开始扫描', on_press=self.start_scan, background_color=(0.2, 0.7, 0.2, 1))
        self.stop_btn = Button(text='停止扫描', on_press=self.stop_scan, disabled=True, background_color=(0.7, 0.2, 0.2, 1))
        scan_layout.add_widget(self.scan_btn)
        scan_layout.add_widget(self.stop_btn)
        
        # 搜索框和搜索模式
        search_layout = BoxLayout(orientation='horizontal', spacing=5, size_hint_y=None, height=40)
        self.search_input = TextInput(text='', hint_text='搜索', multiline=False, size_hint_x=0.7)
        self.search_mode = Spinner(
            text='任意字符',
            values=['任意字符', '备注搜索']
        )
        self.search_input.bind(text=self.on_search_text_change)
        search_layout.add_widget(self.search_input)
        search_layout.add_widget(self.search_mode)
        
        control_layout.add_widget(path_layout)
        control_layout.add_widget(type_scroll)
        control_layout.add_widget(scan_layout)
        control_layout.add_widget(search_layout)
        
        # 文件列表（可滚动）
        self.file_list_layout = ScrollView()
        self.file_container = BoxLayout(orientation='vertical', spacing=5, padding=5)
        self.file_container.bind(minimum_height=self.file_container.setter('height'))
        self.file_list_layout.add_widget(self.file_container)
        
        # 状态栏
        status_layout = BoxLayout(orientation='horizontal', size_hint_y=None, height=30)
        status_label = Label(text='状态: ', size_hint_x=0.3)
        self.status_value = Label(text=self.status_text, size_hint_x=0.7)
        status_layout.add_widget(status_label)
        status_layout.add_widget(self.status_value)
        
        count_layout = BoxLayout(orientation='horizontal', size_hint_y=None, height=30)
        count_label = Label(text='找到: ', size_hint_x=0.3)
        self.count_value = Label(text=self.file_count, size_hint_x=0.7)
        count_layout.add_widget(count_label)
        count_layout.add_widget(self.count_value)
        
        self.root.add_widget(control_layout)
        self.root.add_widget(self.file_list_layout)
        self.root.add_widget(status_layout)
        self.root.add_widget(count_layout)
        
        return self.root
    
    def init_db(self):
        """初始化数据库"""
        try:
            conn = sqlite3.connect(self.db_path)
            c = conn.cursor()
            c.execute('''CREATE TABLE IF NOT EXISTS file_notes
                         (path TEXT PRIMARY KEY, note TEXT)''')
            conn.commit()
            conn.close()
        except Exception as e:
            self.show_popup('数据库错误', f'初始化数据库失败: {str(e)}')
    
    def browse_directory(self):
        """浏览选择目录"""
        # 简单实现，实际应使用Kivy的文件选择器
        self.show_popup('提示', '请手动输入扫描路径')
    
    def on_extensions_change(self, instance, value):
        """文件类型选择变化"""
        self.selected_extensions = value
    
    def on_search_text_change(self, instance, value):
        """搜索文本变化"""
        self.filter_files(value)
    
    def start_scan(self):
        """开始扫描"""
        path = self.path_input.text
        if not path or not os.path.isdir(path):
            self.show_popup('路径错误', '请选择有效的扫描目录')
            return
    
        # 检查是否选择了文件类型
        if not self.selected_extensions:
            self.show_popup('未选择文件类型', '请至少选择一种文件类型进行扫描')
            return
    
        # 重置文件列表
        self.files = []
        self.filtered_files = []
        self.update_file_list()
        self.file_count = '0'
        self.count_value.text = self.file_count
    
        # 启动扫描线程
        self.scan_thread = ScanThread([path], self.selected_extensions, self.on_file_found)
        
        # 更新UI状态
        self.scan_btn.disabled = True
        self.stop_btn.disabled = False
        
        # 显示扫描状态
        type_names = [self.type_selector.file_types.get(ext, ext) for ext in self.selected_extensions]
        self.status_text = f'正在扫描{"、".join(type_names)}文件...'
        self.status_value.text = self.status_text
        
        self.scan_thread.start()
    
    def stop_scan(self):
        """停止扫描"""
        if self.scan_thread and self.scan_thread.is_alive():
            self.scan_thread.stop()
            self.status_text = '正在停止扫描...'
            self.status_value.text = self.status_text
    
    def on_file_found(self, data):
        """处理找到的文件"""
        if 'progress' in data:
            # 更新进度
            pass
        elif 'finished' in data:
            # 扫描完成
            self.scan_btn.disabled = False
            self.stop_btn.disabled = True
            count = len(self.files)
            self.status_text = f'扫描完成，共找到 {count} 个文件'
            self.status_value.text = self.status_text
        else:
            # 找到新文件
            self.files.append(data)
            # 自动过滤
            self.filter_files(self.search_input.text)
            # 更新计数
            self.file_count = str(len(self.filtered_files))
            self.count_value.text = self.file_count
    
    def filter_files(self, search_text):
        """过滤文件列表，支持在文件名和备注中搜索"""
        if not search_text.strip():
            self.filtered_files = self.files.copy()
        else:
            search_lower = search_text.lower()
            search_mode = self.search_mode.text
            
            self.filtered_files = []
            for f in self.files:
                file_path = f['path']
                # 获取文件备注
                note = self.get_note(file_path)
                
                if search_mode == '任意字符':
                    # 同时搜索文件名和备注
                    if search_lower in f['name'].lower() or search_lower in note.lower():
                        self.filtered_files.append(f)
                elif search_mode == '备注搜索':
                    # 只在备注中搜索
                    if search_lower in note.lower():
                        self.filtered_files.append(f)
        
        # 更新文件列表显示
        self.update_file_list()
        # 更新计数
        self.file_count = str(len(self.filtered_files))
        self.count_value.text = self.file_count
    
    def update_file_list(self):
        """更新文件列表显示"""
        # 清空当前列表
        self.file_container.clear_widgets()
        
        # 添加文件项
        for file_info in self.filtered_files:
            file_item = FileItem(file_info, on_select=self.on_file_select)
            self.file_container.add_widget(file_item)
    
    def on_file_select(self, file_info):
        """选择文件时显示操作菜单"""
        popup = FileActionPopup(file_info, on_action=self.handle_file_action)
        popup.open()
    
    def handle_file_action(self, action, file_info):
        """处理文件操作"""
        if action == 'open_file':
            self.open_file(file_info)
        elif action == 'open_location':
            self.open_file_location(file_info)
        elif action == 'copy_path':
            self.copy_file_path(file_info)
        elif action == 'add_note':
            self.add_note(file_info)
        elif action == 'copy_file':
            self.copy_to_custom_folder(file_info)
        elif action == 'rename':
            self.rename_file(file_info)
        elif action == 'delete':
            self.delete_file(file_info)
    
    def open_file(self, file_info):
        """打开文件"""
        try:
            if sys.platform == 'win32':
                os.startfile(file_info['path'])
            elif sys.platform == 'darwin':  # macOS
                subprocess.run(['open', file_info['path']])
            else:  # Linux
                subprocess.run(['xdg-open', file_info['path']])
            self.show_popup('成功', '文件已打开')
        except Exception as e:
            self.show_popup('操作失败', f'无法打开文件: {str(e)}')
    
    def open_file_location(self, file_info):
        """打开文件所在目录"""
        try:
            path = file_info['path']
            directory = os.path.dirname(path)
            
            if sys.platform == 'win32':
                os.startfile(directory)
            elif sys.platform == 'darwin':  # macOS
                subprocess.run(['open', directory])
            else:  # Linux
                subprocess.run(['xdg-open', directory])
        except Exception as e:
            self.show_popup('操作失败', f'无法打开文件位置: {str(e)}')
    
    def copy_file_path(self, file_info):
        """复制文件路径"""
        # Kivy没有直接访问剪贴板的跨平台方式，这里简化处理
        self.show_popup('提示', f'文件路径: {file_info["path"]}\n(在实际应用中应复制到剪贴板)')
    
    def add_note(self, file_info):
        """添加或编辑备注"""
        # 简化实现，实际应使用更复杂的输入界面
        note = self.get_note(file_info['path'])
        
        # 创建输入弹窗
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(text=f"为文件添加备注:\n{file_info['name']}"))
        note_input = TextInput(text=note, multiline=True, size_hint_y=1)
        
        def on_save(instance):
            self.save_note(file_info['path'], note_input.text)
            popup.dismiss()
            self.show_popup('成功', '备注已保存')
        
        save_btn = Button(text='保存', on_press=on_save)
        cancel_btn = Button(text='取消', on_press=lambda x: popup.dismiss())
        
        content.add_widget(note_input)
        button_layout = BoxLayout(spacing=5)
        button_layout.add_widget(save_btn)
        button_layout.add_widget(cancel_btn)
        content.add_widget(button_layout)
        
        popup = Popup(title='添加备注', content=content, size_hint=(0.9, 0.6))
        popup.open()
    
    def copy_to_custom_folder(self, file_info):
        """复制文件到自定义文件夹"""
        # 简化实现
        self.show_popup('提示', '请手动指定目标文件夹')
    
    def rename_file(self, file_info):
        """重命名文件"""
        # 创建重命名弹窗
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(text='请输入新文件名:'))
        name_input = TextInput(text=file_info['name'], multiline=False)
        
        def on_rename(instance):
            new_name = name_input.text.strip()
            if not new_name:
                self.show_popup('错误', '文件名不能为空')
                return
            
            if new_name == file_info['name']:
                popup.dismiss()
                return
            
            try:
                file_path = file_info['path']
                directory = os.path.dirname(file_path)
                new_file_path = os.path.join(directory, new_name)
                
                if os.path.exists(new_file_path):
                    self.show_popup('错误', f'文件名 "{new_name}" 已存在!')
                    return
                
                os.rename(file_path, new_file_path)
                
                # 更新文件信息
                file_info['name'] = new_name
                file_info['path'] = new_file_path
                
                # 刷新列表
                self.update_file_list()
                self.show_popup('成功', f'文件已重命名为 "{new_name}"')
                popup.dismiss()
            except Exception as e:
                self.show_popup('重命名失败', f'无法重命名文件: {str(e)}')
        
        rename_btn = Button(text='重命名', on_press=on_rename)
        cancel_btn = Button(text='取消', on_press=lambda x: popup.dismiss())
        
        content.add_widget(name_input)
        button_layout = BoxLayout(spacing=5)
        button_layout.add_widget(rename_btn)
        button_layout.add_widget(cancel_btn)
        content.add_widget(button_layout)
        
        popup = Popup(title='文件重命名', content=content, size_hint=(0.8, 0.4))
        popup.open()
    
    def delete_file(self, file_info):
        """删除文件"""
        # 创建确认弹窗
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(text=f'确定要删除文件 "{file_info["name"]}" 吗？\n此操作不可撤销。'))
        
        def on_confirm(instance):
            try:
                os.remove(file_info['path'])
                
                # 从列表中移除
                if file_info in self.files:
                    self.files.remove(file_info)
                if file_info in self.filtered_files:
                    self.filtered_files.remove(file_info)
                
                # 刷新列表
                self.update_file_list()
                self.file_count = str(len(self.filtered_files))
                self.count_value.text = self.file_count
                self.show_popup('成功', f'文件 "{file_info["name"]}" 已成功删除')
                popup.dismiss()
            except Exception as e:
                self.show_popup('删除失败', f'无法删除文件: {str(e)}')
        
        confirm_btn = Button(text='删除', on_press=on_confirm, background_color=(0.7, 0.2, 0.2, 1))
        cancel_btn = Button(text='取消', on_press=lambda x: popup.dismiss())
        
        button_layout = BoxLayout(spacing=5)
        button_layout.add_widget(confirm_btn)
        button_layout.add_widget(cancel_btn)
        content.add_widget(button_layout)
        
        popup = Popup(title='确认删除', content=content, size_hint=(0.8, 0.4))
        popup.open()
    
    def get_note(self, file_path):
        """从数据库获取备注"""
        try:
            conn = sqlite3.connect(self.db_path)
            c = conn.cursor()
            c.execute("SELECT note FROM file_notes WHERE path=?", (file_path,))
            result = c.fetchone()
            conn.close()
            return result[0] if result else ""
        except Exception as e:
            self.show_popup('数据库错误', f'获取备注失败: {str(e)}')
            return ""
    
    def save_note(self, file_path, note):
        """保存备注到数据库"""
        try:
            conn = sqlite3.connect(self.db_path)
            c = conn.cursor()
            c.execute("REPLACE INTO file_notes (path, note) VALUES (?, ?)", 
                     (file_path, note))
            conn.commit()
            conn.close()
        except Exception as e:
            self.show_popup('数据库错误', f'保存备注失败: {str(e)}')
    
    def show_popup(self, title, message):
        """显示弹窗消息"""
        content = BoxLayout(orientation='vertical', padding=10, spacing=10)
        content.add_widget(Label(text=message))
        close_btn = Button(text='关闭', on_press=lambda x: popup.dismiss())
        content.add_widget(close_btn)
        
        popup = Popup(title=title, content=content, size_hint=(0.8, 0.4))
        popup.open()
    
    def on_stop(self):
        """应用停止时的清理工作"""
        if self.scan_thread and self.scan_thread.is_alive():
            self.scan_thread.stop()
            self.scan_thread.join(timeout=1)

if __name__ == '__main__':
    MobileScannerApp().run()